package cn.toprog.viewer.controller;

import cn.toprog.viewer.component.Thumbnail;
import cn.toprog.viewer.util.Utilities;
import java.io.File;
import java.io.FileFilter;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TreeView;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;

public class Controller implements Initializable {
    @FXML
    private TreeView<File> folderTree;
    @FXML
    private StackPane folderTreePane;
    @FXML
    private Label selectedFolderLabel;
    @FXML
    private FlowPane thumbnailsPane;
    @FXML
    private Rectangle dragBox;
    @FXML
    private Label labelTotal;
    @FXML
    private Label labelSelected;

    private LoadThumbnailTask task = null; // 加载缩略图的任务
    // 在缩略图中进行拖动时的起点坐标
    private double selectStartX;
    private double selectStartY;
    private boolean dragged;  // 是否进行的拖动选择

    private Clipboard clipboard = Clipboard.getSystemClipboard();
    private ContextMenu popupMenuForThumbnailsPane;
    private ContextMenu popupMenuForThumbnail;

    // shift 选择时，起点缩略图的下标(children中)
    private int shiftSelectStartIndex = 0;

    /**
     * 初始化方法
     *
     * @param location
     * @param resources
     */
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        thumbnailsPane.requestFocus();
        thumbnailsPane.setStyle("-fx-border-style: solid;");
        SplitPane.setResizableWithParent(folderTreePane, false);
        popupMenuForThumbnailsPane = buildPopupMenuForThumbnailsPane();
        popupMenuForThumbnail = buildPopupMenuForThumbnail();

        selectedFolderLabel.textProperty().bind(folderTree.getSelectionModel().selectedItemProperty().asString());

        // 目录树的选中目录发生变化时的监听器
        folderTree.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            thumbnailsPane.getChildren().clear();  // 清除缩略图面板上的缩略图
            shiftSelectStartIndex = 0;             // 重置 shift 选择的起始下标

            // 如果目录树的选中目录发生变化时有加载缩略图的任务正在运行，则取消其运行
            if (task != null && task.isRunning()) {
                task.cancel();  // 取消任务
            }

            File selectedFolder = newValue.getValue(); // 获取目录树当前选中节点对应的目录对象

            // 创建一个图像文件过滤器
            FileFilter imageFileFilter = file -> {
                return Utilities.isImageFile(file);
            };

            //使用过滤器获取当前选中目录中的图像文件
            File[] imageFiles = selectedFolder.listFiles(imageFileFilter);
            // 如果存在需要加载的图片
            if (imageFiles != null && imageFiles.length > 0) {
                // 创建将 imageFiles 中的图像文件加载到 thumbnailsPane 中的任务
                task = new LoadThumbnailTask(imageFiles, thumbnailsPane);
                Thread thread = new Thread(task); // 创建执行task的线程
                thread.setDaemon(true);
                thread.start();
            }
            labelTotal.setText(String.format("%d 个图片文件", imageFiles.length));
        });

        // 设置 thumbnailsPane 的鼠标按下事件
        thumbnailsPane.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                System.out.println("pressed!");
                selectStartX = event.getX();
                selectStartY = event.getY();
            }
        });

        // 设置 thumbnailsPane 的鼠标拖动事件
        thumbnailsPane.setOnMouseDragged(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                if (!dragged) {
                    dragged = true;
                    dragBox.setVisible(true);
                }

                Utilities.fixedRectangle(thumbnailsPane, dragBox, selectStartX, selectStartY, event.getX(), event.getY());

                for (Node node : thumbnailsPane.getChildren()) {
                    Thumbnail thumbnail = (Thumbnail) node;

                    if (Utilities.isIntersected(thumbnail, event.getX(), event.getY(), selectStartX, selectStartY)) {
                        thumbnail.setSelected(true);
                    } else {
                        thumbnail.setSelected(false);
                    }
                }
            }
        });

        // 设置 thumbnailsPane 的鼠标单击事件
        thumbnailsPane.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                System.out.println("clicked!");
                if (dragged) {
                    dragged = false;
                    dragBox.setVisible(false);
                    return;
                }

                Node pickNode = event.getPickResult().getIntersectedNode(); // 返回点击的对象

                // 在某个缩略图上clicked
                if (pickNode instanceof Thumbnail) {
                    if (event.getButton() == MouseButton.PRIMARY) {  // 左键
                        if (event.isShiftDown()) {
                            int pickNodeIndex = thumbnailsPane.getChildren().indexOf(pickNode); // 点击缩略图的下标
                            int s = pickNodeIndex < shiftSelectStartIndex ? pickNodeIndex : shiftSelectStartIndex;
                            int e = pickNodeIndex > shiftSelectStartIndex ? pickNodeIndex : shiftSelectStartIndex;
                            for (int i = 0; i < thumbnailsPane.getChildren().size(); i++) {
                                Thumbnail t = (Thumbnail) thumbnailsPane.getChildren().get(i);
                                t.setSelected(i >= s && i <= e);
                            }
                        } else if (event.isControlDown()) {
                            ((Thumbnail) pickNode).setSelected(!((Thumbnail) pickNode).isSelected());
                        } else {
                            thumbnailsPane.getChildren().forEach(node -> {
                                ((Thumbnail) node).setSelected(false);
                            });
                            ((Thumbnail) pickNode).setSelected(true);
                        }
                    } // end of 左键

                    if (event.getButton() == MouseButton.SECONDARY) {  // 右键
                        // 如果右击的缩略图原来未选中
                        if (!((Thumbnail) pickNode).isSelected()) {
                            thumbnailsPane.getChildren().forEach(node -> {
                                ((Thumbnail) node).setSelected(false);
                            });
                            ((Thumbnail) pickNode).setSelected(true);
                        }
                        // TODO: 弹出右键菜单
                        System.out.println("Popup menu 缩略图");
                    } // end of 右键
                } // end of 点击缩略图

                // 直接点击在面板上
                if (pickNode == thumbnailsPane) {
                    if (!(event.isShiftDown() || event.isControlDown())) {
                        thumbnailsPane.getChildren().forEach(node -> {
                            ((Thumbnail) node).setSelected(false);
                        });
                    }
                    if (event.getButton() == MouseButton.SECONDARY) {
                        // TODO: 弹出右键菜单
                        System.out.println("Popup menu 面板");
                    }
                } // end of 点击面板
            }
        });

        thumbnailsPane.setOnMouseReleased(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                System.out.println("released!");
                Node pickNode = event.getPickResult().getIntersectedNode(); // 返回点击的对象
                if (pickNode instanceof Thumbnail) { // 在某个缩略图上释放鼠标
                    if (!event.isShiftDown()) {
                        shiftSelectStartIndex = thumbnailsPane.getChildren().indexOf(pickNode);
                    }
                }
            }
        });

        thumbnailsPane.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {
            @Override
            public void handle(ContextMenuEvent event) {
                if (event.getPickResult().getIntersectedNode() == thumbnailsPane) {
                    popupMenuForThumbnailsPane.getItems().get(0).setDisable(clipboard.getFiles().size() == 0);
                    popupMenuForThumbnailsPane.hide();
                    popupMenuForThumbnailsPane.show(thumbnailsPane, event.getScreenX(), event.getScreenY());
                }
            }
        });

    } // end of initialize method

    private ContextMenu buildPopupMenuForThumbnailsPane() {
        MenuItem pasteItem = new MenuItem("粘贴");
        pasteItem.setOnAction(event -> {
            System.out.println("do paste!");
            System.out.println(clipboard.getFiles());

        });
        ContextMenu popupMenu = new ContextMenu();
        popupMenu.getItems().add(pasteItem);
        return popupMenu;
    }

    private ContextMenu buildPopupMenuForThumbnail() {
        MenuItem copyItem = new MenuItem("复制");
        copyItem.setOnAction(event -> {
            System.out.println("do copy!");
            clipboard.clear();
            ClipboardContent content = new ClipboardContent();
            List<File> list = new ArrayList<>();
            for (Node node : thumbnailsPane.getChildren()) {
                Thumbnail t = (Thumbnail) node;
                if (t.isSelected()) {
                    list.add(t.getImageFile());
                }
            }
            content.putFiles(list);
            clipboard.setContent(content);
        });

        MenuItem cutItem = new MenuItem("剪切");
        cutItem.setOnAction(event -> {
            System.out.println("do cut!");
        });

        MenuItem deleteItem = new MenuItem("删除");
        deleteItem.setOnAction(event -> {
            System.out.println("do delete!");
        });

        MenuItem renameItem = new MenuItem("重命名");
        renameItem.setOnAction(event -> {
            System.out.println("do rename!");
        });

        ContextMenu popupMenu = new ContextMenu();
        popupMenu.getItems().addAll(copyItem, cutItem, new SeparatorMenuItem(), deleteItem, new SeparatorMenuItem(), renameItem);
        return popupMenu;
    }

    /**
     * 内部类，加载缩略图的任务
     */
    private class LoadThumbnailTask extends Task<Integer> {
        private File[] imageFiles; // 目录中的图片文件数组
        private FlowPane pane;     // 旋转缩略图的窗格

        public LoadThumbnailTask(File[] imageFiles, FlowPane pane) {
            this.imageFiles = imageFiles;
            this.pane = pane;
            this.updateProgress(0, 1);
        }

        @Override
        protected Integer call() throws Exception {
            int i = 1, max = imageFiles.length;

            for (File file : imageFiles) {
                // 检测到线程(任务)被中断，退出循环
                if (this.isCancelled()) {
                    break;
                }
                Platform.runLater(() -> {
                    /*
                     * 由于这里的代码是由JavaFX Application线程在特定时间执行的，因此有可能发生task被Cancel之后，
                     * 这个线程还执行几个，这样就会在新目录的缩略图中绘制上个目录的几张图片。 因此，在检测到task被取消后就直接返回。
                     */
                    if (this.isCancelled()) {
                        return;
                    }
                    Thumbnail thumbnail = new Thumbnail(file); // 创建一个缩略图
                    thumbnail.setContextMenu(popupMenuForThumbnail);

                    pane.getChildren().add(thumbnail);
//                    numberOfThumbnailsLabel.setText(String.format("共 %d 张图片", thumbnailPane.getChildren().size()));
                });
                this.updateProgress(i, max); // 更新进度
                i++;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // 为了避免线程(任务)在sleep过程中被中断，使用异常处理做二次检测
                    if (this.isCancelled()) {
                        break;
                    }
                }
            }
            return pane.getChildren().size();
        } // end of call method
    } // end of class LoadThumbnailTask
}
